<template>
  <div>
    <div>
      <el-input style="width: 200px; margin: 0 5px" placeholder="文件名称(选填)" v-model="fileNameSearch"></el-input>
      <el-select v-model="creatorSearch" filterable placeholder="选择归属人" style="width: 150px; margin: 0 5px">
        <el-option v-for="item in userOptions" :key="item.value" :label="item.label" :value="item.value">
        </el-option>
      </el-select>

      <el-button type="primary" @click="load(1)">查询</el-button>
      <el-button type="primary" @click="reset">重置</el-button>
    </div>
    <div style="margin: 10px 0">
<!--      <el-button type="primary" plain @click="handleAddOrEdit">新增</el-button>-->
      <el-button type="danger" plain @click="handleDelBatch">批量删除</el-button>
    </div>
    <!--  整个表格，有多选框 -->
    <el-table v-loading="loading" element-loading-text="拼命加载中" :data="tableData" stripe :header-cell-style="{backgroundColor: 'aliceblue',color: '#666'}"
              @selection-change="handleSelectionChange">
      <!--    复选框-->
      <el-table-column type="selection" width="55" align="center"></el-table-column>
      <el-table-column prop="id" label="ID" width="80" align="center">
        <template v-slot="scope">
          <el-tooltip class="item" effect="dark" content="点击复制文件链接">
            <span @click="copyFilePath(scope.row.id)" style="cursor: pointer;">{{ scope.row.id }}</span>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column prop="fileName" label="文件名称" width="300px" show-overflow-tooltip>
        <template v-slot="scope">
          <el-tooltip class="item" effect="dark" content="双击打开文件">
            <span @dblclick="openFile(scope.row)" style="cursor: pointer;">{{ scope.row.fileName }}</span>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column prop="fileType" label="文件类型" width="100">
        <template v-slot="scope">
          <el-tag :type="getStatusType(scope.row.fileType)">{{getStatusText(scope.row.fileType)}}</el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="fileSize" label="文件大小" width="80"></el-table-column>
      <el-table-column prop="downCount" label="下载次数" width="140"></el-table-column>
      <el-table-column prop="username" label="归属人" width="140"></el-table-column>
      <el-table-column prop="creatTime" label="上传时间" width="140"></el-table-column>
<!--      <el-table-column prop="modifier" label="修改者" width="140"></el-table-column>-->
<!--      <el-table-column prop="modifierName" label="修改时间" width="140"></el-table-column>-->
      <el-table-column prop="remark" label="备注"></el-table-column>
      <el-table-column fixed="right" label="操作" align="center" width="180px">
        <template v-slot="scope">
<!--          <el-button size="mini" type="primary" plain @click="handleAddOrEdit(scope.row)">编辑</el-button>-->
          <el-button v-if="isShow(scope.row)" size="mini" type="danger" plain @click="handleDel(scope.row)">删除</el-button>
          <el-button v-if="isShow(scope.row)" size="mini" type="success" plain @click="downloadFile(scope.row)">下载</el-button>
        </template>
      </el-table-column>
    </el-table>

    <div style="margin: 10px 0;text-align: center">
      <el-pagination @current-change="handleCurrentChange"
                     :current-page="pageNum"
                     :page-size="pageSize"
                     layout="total,prev,pager,next"
                     :total="total">
      </el-pagination>
    </div>

    <!-- 新增表单需要弹窗包裹 / close-on-click-model点击弹窗外不会关闭-->
    <el-dialog title="公告信息"
               :visible.sync="formVisible"
               width="40%"
               :close-on-click-model="false">
      <el-form :model="form"
               label-width="80px"
               style="padding-right: 20px"
               :rules="rules"
               ref="formRef">

        <el-form-item label="标题" prop="title">
          <el-input v-model="form.title" placeholder="标题"></el-input>
        </el-form-item>

        <!-- prop 与rules字段绑定     -->
        <el-form-item label="内容" prop="content">
          <el-input type="textarea" v-model="form.content" placeholder="内容"></el-input>
        </el-form-item>

        <!--      <el-form-item label="作者" prop="author">-->
        <!--        <el-input v-model="form.author" placeholder="作者"></el-input>-->
        <!--      </el-form-item>-->

        <!--      <el-form-item label="创建时间" prop="datetime">-->
        <!--        <el-input v-model="form.creatTime" placeholder="创建时间"></el-input>-->
        <!--      </el-form-item>-->

        <!--      <el-form-item label="更新时间" prop="datetime">-->
        <!--        <el-input v-model="form.updateTime" placeholder="更新时间"></el-input>-->
        <!--      </el-form-item>-->

        <el-form-item label="备注" prop="remark">
          <el-input v-model="form.remark" placeholder="备注"></el-input>
        </el-form-item>

      </el-form>

      <div slot="footer" class="dialog-footer">
        <el-button @click="formVisible = false">取消</el-button>
        <el-button type="primary" @click="save">保存</el-button>
      </div>
    </el-dialog>

  </div>
</template>

<script>

export default {
  name: "File",
  data(){
    return {
      tableData: []//表数据
      ,pageNum: 1//当前页码
      ,pageSize: 10//每页数量
      ,fileNameSearch: '' //搜索文件名
      ,creatorSearch: ''//搜索归属人
      ,content: ''
      ,total: 0 //数据总条数
      ,formVisible: false //默认不显示新增表单弹窗
      ,form: {}
      ,user: JSON.parse(localStorage.getItem('userInfo') || '{}')
      ,rules: {
        title: [
          {required: true,message: '输入标题',trigger: 'blur'}
        ],
        content: [
          {required: true,message: '输入内容',trigger: 'blur'}
        ]
      }
      ,ids: []
      ,loading: true
      ,userOptions: []
    }
  },
  created() {
    this.load();
  },
  //安装
  mounted() {
    this.initUsersOptions()
  },
  methods: {
    reset(){
      this.fileNameSearch = ''
      this.creatorSearch = ''
      this.load()
    },
    load(pageNum){
      if (pageNum) this.pageNum = pageNum;  //分页查询时自动切换到第一页
      this.$request.get('/file/findByPage',{
        params:{
          pageNum: this.pageNum,
          pageSize: this.pageSize,
          fileName: this.fileNameSearch,
          creator: this.creatorSearch
        }
      }).then(res => {
        if (res.data){
          if (res.data.records){
            // this.tableData = res.data
            this.tableData = res.data.records  //若records不显示可替换为List
          }else{
            this.$message.warning("res.data.records不存在")
          }
          this.total = res.data.total
        }else {
          this.$message.error("接口未返回数据，请重新登录")
        }
        this.loading = false
      })
    },
    //切换页码
    handleCurrentChange(pageNum){
      // this.pageNum = pageNum //方法传递过来参数就不用赋值了
      this.load(pageNum)
    },
    //新增弹窗事件||编辑弹窗
    //注意：row无论在哪种模式，永远不为空，只是值内容多少的区别，所以同函数无法精确区分两种模式，要么分函数，要么根据内容来区分
    handleAddOrEdit(row){
      // this.form = row.id ?  JSON.parse(JSON.stringify(row)) : {}
      //判断是否编辑模式，默认false
      if (row.id){
        this.isEditMode = true;
        this.form = JSON.parse(JSON.stringify(row)) //弹窗带出来信息,浅拷贝是内存指向，深拷贝是开区域赋值
      }else {
        this.isEditMode = false; //其实不用写，默认就是false
        this.form = {} //新增数据时清空表单
      }

      this.formVisible = true //显示弹窗
    },
    //发送save请求
    sendSave(){
      //发送请求
      this.$request({
        //有id就是编辑
        method: this.form.id ? 'PUT' : 'POST',
        data: this.form,
        url: this.form.id ? '/file/update' : '/file/save'
      }).then(res => {
        if (res.code === '200'){
          //保存成功
          this.$message.success('保存成功')
          this.formVisible = false;
          this.load(this.pageNum)
        }else {
          this.$message.error(res.msg) //错误信息
        }
      })
    },
    //新增保存
    save(){
      //校验表单
      this.$refs.formRef.validate((valid) => {
        if (valid){
          this.sendSave()
        }else {
          this.$message.warning("表单校验未通过")
        }
      })
    },
    downloadFile(row){
      // 检查 row 是否存在
      if (!row) {
        this.$message.error('未提供有效的文件信息');
        return;
      }

      if (this.isShow(row)){
        // 检查 row.id 是否存在
        if (!row.id) {
          this.$message.error('文件 ID 缺失，无法下载');
          return;
        }

        try {
          let param = '&type=attachment&id='+row.id;
          // 检查 $apiUrl 和 user.token 是否存在
          if (!this.$apiUrl || !this.user.token) {
            this.$message.error('缺少必要的下载信息，请重新登录');
            return;
          }

          const url = this.$apiUrl +'/file/download?token=' +this.user.token + param;

          // 使用 fetch API 下载文件
          fetch(url)
            .then(response => {
              if (!response.ok) {
                throw new Error('网络响应失败');
              }
              return response.blob();
            })
            .then(blob => {
              // 创建一个临时的 URL
              const blobUrl = URL.createObjectURL(blob);
              // 创建一个隐藏的 <a> 元素
              const link = document.createElement('a');
              link.href = blobUrl;
              // 假设文件名在 row.fileName 中
              link.download = row.fileName;
              link.style.display = 'none';
              document.body.appendChild(link);
              // 模拟点击链接
              link.click();
              // 清理临时 URL
              URL.revokeObjectURL(blobUrl);
              document.body.removeChild(link);
              this.load(this.pageNum);
            })
            .catch(error => {
              console.error('文件下载出错:', error);
              this.$message.error('文件下载失败，请稍后重试');
            });
        } catch (error) {
          console.error('文件下载出错:', error);
          this.$message.error('文件下载失败，请稍后重试');
        }
      }else {
        this.$message.error("你不是文件上传者，不可下载！");
      }
    },
    //单个删除
    handleDel(row){
      this.$confirm('确认删除《'+row.fileName+'》记录吗？','确认删除',{type: "warning"}).then(ok => {
        this.$request.delete('/file/delete/'+row.id).then(res => {
          if (res.code == '200'){
            this.$message.success("删除成功")
          }else {
            this.$message.error("删除失败："+res.msg)
          }
          this.load(this.pageNum) //刷新表格
        })
      }).catch(() => {}) //catch捕捉先不做处理
    },
    //批量删除之前--多选框，参数是选中的行对象
    handleSelectionChange(rows){
      if (rows.some(row => !this.isShow(row))){
        this.$message.error("不要试图操作别人的文件");
        return
      }
      this.ids = rows.map(row => row.id) //流和表达式，将行id提取出来存入数组
    },
    //批量删除
    handleDelBatch(){
      //校验：点击批量删除按钮之前，未选择多选框时提示
      if (!this.ids.length){
        this.$message.warning('请选择需要批量删除的记录！')
        return
      }
      this.$confirm('你确认批量删除['+this.ids+']这些记录吗？','确认删除',{type: "warning"}).then(ok => {
        this.$request.delete('/file/deleteBatch',{data: this.ids}).then(res => {
          if (res.code == '200'){
            this.$message.success("批量删除成功")
          }else {
            this.$message.error("批量删除失败:"+res.msg)
          }
          this.load(this.pageNum) //刷新表格
        })
      }).catch(() => {}) //catch捕捉先不做处理
    },
    //是否公开 改变事件
    openChange(form){
      // this.form = form; //这样不合适，是属于直接指向内存地址，浅拷贝会直接改变影响数据库原本数据
      this.form = JSON.parse(JSON.stringify(form))  //变为与行对象没有关系，而是重新赋值，新建自己的内存空间，互不影响，属于深拷贝
      //调用更新，无需校验，直接发请求
      this.sendSave()
    },

    getStatusText(status) {
      switch (status) {
        case 1:
          return '附件关联';
        case 2:
          return '工具生成';
        case 3:
          return '用户上传';
        case 4:
          return '特殊文件';
        default:
          return '未知';
      }
    },
    getStatusType(status) {
      switch (status) {
        case 1:
          return 'primary';
        case 2:
          return 'warning';
        case 3:
          return 'success';
        case 4:
          return 'danger';
        default:
          return 'info'; // 默认没有特殊样式
      }
    },
    isShow(row){
      return (row.userId === this.user.id);
    },
    openFile(row) {
      if (!this.isShow(row)) {
        this.$message.error("你没有权限打开此文件！");
        return;
      }
      
      const fileName = row.fileName;
      const ext = fileName.split('.').pop().toLowerCase();
      const officeTypes = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'];
      
      if (officeTypes.includes(ext)) {
        let documentType;
        if (['doc', 'docx'].includes(ext)) {
          documentType = 'word';
        } else if (['xls', 'xlsx'].includes(ext)) {
          documentType = 'cell';
        } else if (['ppt', 'pptx'].includes(ext)) {
          documentType = 'slide';
        }
        
        const fileUrl = encodeURIComponent(`${this.$apiUrl}/file/download?token=${this.user.token}&type=preview&id=${row.id}`);
        // 使用环境变量动态获取OnlyOffice服务地址，保留原地址作为回退值
        const onlyOfficeUrl = `${process.env.VUE_APP_ONLY_OFFICE_URL || 'https://unit.sangu.js.cn:449'}/web-apps/apps/editor/main/index.html?fileUrl=${fileUrl}&documentType=${documentType}`;
        
        window.open(onlyOfficeUrl, '_blank');
      } else {
        this.$message.info("不支持的文件类型，无法在线编辑！");
      }
    },
    async copyFilePath(id) {
      if (id){
        let param = this.$apiUrl +'/file/download?token=' +this.user.token + '&type=preview&id='+id;

        try {
          // 检查浏览器是否支持 clipboard API
          if (!navigator.clipboard) {
            console.error('浏览器不支持 clipboard API');
            this.$message.error('您的浏览器或传输协议暂不支持复制');
            return;
          }

          // 尝试复制文本到剪贴板
          await navigator.clipboard.writeText(param);
          this.$message.success('文件路径已复制到剪切板');
        } catch (err) {
          // 捕捉任何可能的错误，包括权限错误等
          if (err.name === 'NotAllowedError') {
            console.error('权限错误：页面需要在用户交互下才能访问剪贴板');
            this.$message.error('请允许页面访问剪贴板后重试');
          } else if (err.name === 'AbortError') {
            console.error('操作被中断');
            this.$message.error('复制操作被中断');
          } else {
            console.error('无法复制文件路径：', err);
            this.$message.error('复制文件路径失败，请重试');
          }
        }
      }
    },
    //初始化用户选择框
    initUsersOptions() {
      this.$request({
        method: 'GET',
        url: '/user/getSelect',
      }).then((res) => {
        if (res.code === '200') {
          this.userOptions = res.data
        } else {
          this.$message.error(res.msg) //错误信息
          return false
        }
      })
    },

  }
}
</script>

<style>
</style>